/*
* INSANE - Interactive Structural Analysis Environment
*
* Copyright (C) 2003-2005
* Universidade Federal de Minas Gerais
* Escola de Engenharia
* Departamento de Engenharia de Estruturas
* 
* Author's email :    insane@dees.ufmg.br
* Author's website :  http://www.dees.ufmg.br/insane
* 
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
package br.ufmg.dees.insane.prep;

import java.util.List;

import br.ufmg.dees.insane.model.geo.GCurve;
import br.ufmg.dees.insane.model.geo.GPoint;
import br.ufmg.dees.insane.model.geo.GRegion;

public class LoftingToLagranQ extends Lofting{
	
//*****************************************************************************
	
	public LoftingToLagranQ(int ln, int le, int nppe, int ne, GRegion rg){
		this.lastNode = ln;
		this.lastElement = le;
		this.nPointsPerElement = nppe;
		
		this.transverseCurvePoints = (( (int)Math.sqrt(nppe) )-1)*ne + 1;
		
		this.region = rg;
		
		this.mapNodes();
		this.conectivite();
	}
	
//*****************************************************************************
	
	private void mapNodes(){
		int nPartsBetweenCurves = this.transverseCurvePoints - 1;
		
		List curves = this.region.getCurves();
		GPoint[] curve1 = ((GCurve)curves.get(0)).getDiscrete();
		GPoint[] curve2 = ((GCurve)curves.get(1)).getDiscrete();
		
		int nPoints1 = curve1.length;
		
		double x, y;
		for (int i = 0; i <= nPartsBetweenCurves; i++) {
			double v = (double)i/(nPartsBetweenCurves);
			for (int j = 0; j < nPoints1; j++) {
				lastNode++;
				x = (1.0-v)*curve1[j].getX()+v*curve2[j].getX();
				y = (1.0-v)*curve1[j].getY()+v*curve2[j].getY();
				MapNode mn = new MapNode(x, y, lastNode);
				if ( i==0 || j==0 || i==nPartsBetweenCurves || j==(nPoints1-1) ) {
					mn.setBoundary( true );
				}
				this.nodes.add(mn);
			}
		}
	}
	
//*****************************************************************************
	
	private void conectivite(){
		List curves = this.region.getCurves();
		GPoint[] curve1 = ((GCurve)curves.get(0)).getDiscrete();
		int nPoints1 = curve1.length;
		int nPointsElementSide = (int)Math.sqrt(nPointsPerElement);
		
		int nElements1 = (nPoints1 - 1)/(nPointsElementSide - 1);
		int nElements2 = (transverseCurvePoints - 1)/(nPointsElementSide - 1);
		int element = this.lastElement;
		MapNode[] conec = new MapNode[nPointsElementSide*nPointsElementSide];
		MapNode[] bound = new MapNode[4*(nPointsElementSide-1)];
		for (int i = 0; i < nElements2; i++) {
			for (int j = 0; j < nElements1; j++) {
				element++;
				int no = -1;
				//	algoritimo para gerar o contorno do elemento no sentido anti-horario
				// lado superior
				for (int k = nPointsElementSide; k > 0; k--) {
					no++;
					bound[no] = (MapNode)nodes.get( (nPoints1)*(nPointsElementSide-1)*i+(nPointsElementSide-1)*j+k - 1 );
				}
				// lado esquerdo
				for (int k = 1; k <= (nPointsElementSide-2); k++) {
					no++;
					bound[no] = (MapNode)nodes.get( (1+(nPointsElementSide-1)*i)*(nPoints1)+(nPointsElementSide-1)*j+(nPoints1)*(k-1)+1 - 1 );
				}
				// lado inferior
				for (int k = 1; k <= nPointsElementSide; k++) {
					no++;
					bound[no] = (MapNode)nodes.get( (nPoints1)*(nPointsElementSide-1)*(i+1)+(nPointsElementSide-1)*j+k - 1 );
				}
				// lado direito
				for (int k = (nPointsElementSide-2); k >= 1; k--) {
					no++;
					bound[no] = (MapNode)nodes.get( (1+(nPointsElementSide-1)*i)*(nPoints1)+(nPointsElementSide-1)*(j+1)+(nPoints1)*(k-1)+1 - 1 );
				}
				no = -1;
				//	algoritimo para gerar a conectividade do elemento
				for (int m = 0; m < nPointsElementSide; m++) {
					for (int n = 0; n < nPointsElementSide; n++) {
						no++;
						conec[no] = (MapNode)nodes.get( i*(nPointsElementSide-1)*nPoints1+j*(nPointsElementSide-1)+m*nPoints1+n+1 - 1 );
					}
				}
				MapElement me = new MapElement(element, conec, bound);
				me.setType('Q','L');
				this.elements.add(me);
			}
		}
	}
	
//*****************************************************************************
}

